local e_util = require "libs/entutil"
local status = {
	-- description 必须填写
	all = {
		description = "默认模式：显示攻击范围、指向箭头、海星清远古",
	},
	hide = {
		description = "独行模式：关闭掉提示箭头",	-- 其实已经可以取消这个了, 因为已经修复了
		arrow_should_hide = true,
	},
	seeds = {
		description = "种地模式：额外提示种子",
		currentTrack = {seeds = {color = "green", dist_away = 8, dist_show = 8}},
	},
	close = {
		description = "关闭模式：关闭攻击范围，关闭指向箭头，关闭海星清远古提示",
		arrow_should_hide = true,
		range_should_hide = true,
		star_should_hide = true,
	}
}
local KEY = "all"
GLOBAL.MOD_ShroomCake.getAttackDistKey = function()
	return KEY
end

-- 仇恨距离和攻击距离
local TARGET_DIST_AUTO = {
	"WALRUS", "KNIGHT", "BISHOP", "ROOK", "SLURTLE",
	"SPAT", "WORM", "TALLBIRD",
	"ALTERGUARDIAN_PHASE1","ALTERGUARDIAN_PHASE2",
	"ALTERGUARDIAN_PHASE3",
	-- BOSS
	"MINOTAUR", --"WARG"
}
local ATTACK_RANGE_AUTO = {
	"TALLBIRD", "BUZZARD", "TEENBIRD", "SQUID","SLURTLE",
	"SPIDER_WATER", "TENTACLE_PILLAR_ARM","WORM",
	"CATCOON","SLURPER","WALRUS",
	-- BOSS
	"MOSSLING","BEEGUARD","MOOSE",--"BEARGER",
	"BEEQUEEN",
	"DEERCLOPS","LORDFRUITFLY","WARG","SPIDERQUEEN","MALBATROSS",
	"KLAUS","DRAGONFLY",

	-- 吞噬距离 / 停止攻击距离
	"EYEPLANT",
	"shadowthrall_hands","shadowthrall_horns","shadowthrall_wings",
}

local RANGE_HIDE
local rangeTable = require("QAQ/rangetable")
-- 没有必要去统计所有的inst_atk_range, range_should_hide会自动控制
local function ACTIVATE_ATTACK_RANGE()
	local function apply(prefab, color, range, always, add, quick)
		local prefab = string.lower(prefab)
		local item = string.format("atkr_%s", range)
		AddPrefabPostInit(prefab, function(inst)
			local flushTime = quick and 0.1 or 1
			local inst_atk_range
			inst:DoPeriodicTask(flushTime, function()
				inst[item] = inst_atk_range
				if not inst_atk_range then
					inst_atk_range = GLOBAL.SpawnPrefab("hrange"):setVisable(false):setParentScale(inst, range+add):setColor(color)
					if prefab == "tallbird" then
						inst_atk_range:AddTag(prefab)		-- 此处为科雷的bug
					end
				else
					if RANGE_HIDE then
						inst_atk_range:setVisable(false):setParentHighLight(inst, color)
						return
					end
					if GetAggro(inst) == GLOBAL.ThePlayer then
						inst_atk_range:setParentHighLight(inst, true):setVisable(true)
					elseif always then
						inst_atk_range:setVisable(true):setColor(color)
					else
						inst_atk_range:setParentHighLight(inst, color)
						-- local leader = GetLeader(inst)
						if GLOBAL.ThePlayer and inst:GetPosition():DistSq(GLOBAL.ThePlayer:GetPosition()) > 9*range*range 
						or GetLeader(inst)
						then
							inst_atk_range:setVisable(false)
						else
							inst_atk_range:setVisable(true)
						end
					end
				end
			end)
		end)
	end
	for _, animals in pairs(rangeTable.attack_range) do
		for _, prefab in pairs(animals.prefabs)do
			for _, circle in pairs(animals.rotary)do
				apply(prefab, circle[1], circle[2], animals.always, 0.5)
			end
		end
	end
	for _, animals in pairs(rangeTable.target_range) do
		for _, prefab in pairs(animals.prefabs)do
			for _, circle in pairs(animals.rotary)do
				apply(prefab, circle[1], circle[2], animals.always, 0, animals.quick)
			end
		end
	end
	for _,prefab in pairs(TARGET_DIST_AUTO) do
		local prefab = string.upper(prefab)
		local range = GLOBAL.TUNING[string.format("%s_TARGET_DIST", prefab)]
			or GLOBAL.TUNING[string.format("%s_TARGETRANGE", prefab)]
		if range then
			apply(prefab, "blue", range, false, 0)
		end
	end
	for _,prefab in pairs(ATTACK_RANGE_AUTO) do
		local prefab = string.upper(prefab)
		-- sb
		local range = GLOBAL.TUNING[string.format("%s_ATTACK_DIST", prefab)] 
			or GLOBAL.TUNING[string.format("%s_HIT_RANGE", prefab)]
			or GLOBAL.TUNING[string.format("%s_ATTACK_RANGE", prefab)]
			or GLOBAL.TUNING[string.format("%s_ATTACKRANGE", prefab)]
		if range then
			apply(prefab, "blue", range, false, 0.5)
		end
	end
end
ACTIVATE_ATTACK_RANGE()

local function animal_track(inst)
	local next_thing
	inst:DoPeriodicTask(0.5, function()
		if e_util:GetAnim(inst) ~= "idle" then
			return
		end
		if RANGE_HIDE then return end
		if inst and inst:IsValid() and inst.Transform then
			local x,y,z = inst.entity:LocalToWorldSpace(0,0,-40)
			if not next_thing then
				next_thing = GLOBAL.TheSim:FindEntities(x,0,z, 10, {"dirtpile"}, { "locomotor", "INLIMBO",'FX','DECOR','NOCLICK','player'})[1]
			 		or GLOBAL.TheSim:FindEntities(x,0,z, 10, {"_health"}, {'FX','DECOR','INLIMBO','NOCLICK', 'player'})[1]
			end
			if next_thing then
				local col = (next_thing:HasTag("koalefant") and "CHOCOLATE")
					or (next_thing:HasTag("spat") and "TEAL")
					or (next_thing:HasTag("warg") and "RED")
					or (next_thing:HasTag("lightninggoat") and "LIGHTGOLD")
					or "blue"
				GLOBAL.SpawnPrefab("huxi_arrow"):setColor(col):ping(inst, next_thing)
			end
		end
	end)
end
-- 脚印追踪
AddPrefabPostInit("animal_track",animal_track)


-- 保持追踪
-- 追踪的物体保持高亮, 且人物脚下有箭头指示
local Tracks = {}
local track_should_hide_table = {}
local function getColor(inst)
	return inst.prefab and rangeTable.track_range[inst.prefab] or (status[KEY].currentTrack and status[KEY].currentTrack[inst.prefab] and status[KEY].currentTrack[inst.prefab].color) or "RED"
end
local function goAway(arrow, color)
	GLOBAL.SpawnPrefab("huxi_arrow"):setColor(color):pingPos(GLOBAL.ThePlayer:GetPosition(), arrow.lastPos)
	arrow:Hide()
end
local TRACK_HIDE
local function ACTIVATE_TRACK()
	local function keep_track(world)
		-- 只运行一个任务可有效缓解多个物品造成卡顿的情况
		world:DoPeriodicTask(.01, function()
			if TRACK_HIDE then return end
			for inst,arrow in pairs(Tracks)do
				arrow:collect(GLOBAL.ThePlayer, inst)
				-- 距离过远
				if not inst:IsValid() then
					-- goAway(arrow)	-- 不必炫技
					arrow:Hide()
					Tracks[inst] = nil
				else
					arrow.lastPos = inst:GetPosition()
					local dist = math.sqrt(arrow:GetPosition():DistSq(arrow.lastPos))
					if inst:HasTag("INLIMBO") or dist > 80 or track_should_hide_table[inst.prefab] then
						inst.AnimState:SetLightOverride(0)
						arrow:Hide()
					elseif dist < (arrow.dist_away or 20) and arrow.allow_away then
						inst.AnimState:SetLightOverride(1)
						goAway(arrow, getColor(inst))
						arrow.allow_away = false
					elseif dist > (arrow.dist_show or 36) then
						inst.AnimState:SetLightOverride(1)
						arrow:Show()
						arrow.allow_away = true
					end
				end
			end
		end)
	end

	local function track_prefab_with_color(prefab, info)
		AddPrefabPostInit(prefab, function(inst)
			inst:DoTaskInTime(1, function()
				local tp = type(info)
				if tp == "string" then
					Tracks[inst] = GLOBAL.SpawnPrefab("huxi_arrow"):setColor(info):hide()
				elseif tp == "table" then
					Tracks[inst] = GLOBAL.SpawnPrefab("huxi_arrow"):setColor(info.color):hide()
					for k,v in pairs(info)do
						Tracks[inst][k] = v
					end
				end
			end)
		end)
	end
	
	for prefab, color in pairs(rangeTable.track_range)do
		track_prefab_with_color(prefab, color)
	end
	for _,t in pairs(status)do
		if type(t.currentTrack) == "table" then
			for prefab, i in pairs(t.currentTrack)do
				track_prefab_with_color(prefab, i)
			end
		end
	end
	AddPrefabPostInit("world", function(inst)
		inst:ListenForEvent("playeractivated", keep_track)
	end)

end
ACTIVATE_TRACK()


-- 海星清远古
-- local Marks = {}
-- local STAR_HIDE
-- local function ACTIVATE_STAR()
-- 	for _,prefab in pairs(rangeTable.starfish_range)do
-- 		AddPrefabPostInit(prefab,function(inst)
-- 			inst:DoPeriodicTask(0.4, function()
-- 				if (not STAR_HIDE) and inst.GUID then
-- 					local id = string.format("Huxi_%s", inst.GUID)
-- 					if not Marks[id] then
-- 						Marks[id] = SpawnMark(inst)
-- 					end
-- 				end
-- 			end)
-- 		end)
-- 	end
-- end
-- ACTIVATE_STAR()

local function SortData()
	local data = status[KEY]
	TRACK_HIDE = data.arrow_should_hide
	RANGE_HIDE = data.range_should_hide
	-- STAR_HIDE = data.star_should_hide
	if TRACK_HIDE then
		for inst,arrow in pairs(Tracks)do
			if inst:IsValid() then
				inst.AnimState:SetLightOverride(0)
				goAway(arrow, getColor(inst))
			end
		end
	else
		for inst,arrow in pairs(Tracks)do
			if inst:IsValid() then
				inst.AnimState:SetLightOverride(1)
				arrow:Show()
			end
		end
		for key,t in pairs(status)do
			if type(t.currentTrack) == "table" then
				for prefab, i in pairs(t.currentTrack)do
					track_should_hide_table[prefab] = key ~= KEY
				end
			end
		end
	end
	-- if STAR_HIDE then
	-- 	for id,mark in pairs(Marks)do
	-- 		for _,inst in pairs(mark)do
	-- 			inst:Remove()
	-- 		end
	-- 	end
	-- 	Marks = {}
	-- end
end


local Data = "ATK_DIST"

local function OnWorldPostInit(inst)
    inst:ListenForEvent("playeractivated", function()
        local info = LoadModData(Data)
		KEY = (type(info) == "nil" and "all") or (status[info] and info or "all")
		SortData()
    end)
end
AddPrefabPostInit("world", OnWorldPostInit)

local t_util = require "libs/tableutil"
local function switchKEY()
	KEY = t_util:GetNextLoopKey(status, KEY)
	SortData()
	TIP("范围追踪", "pink", status[KEY].description, "chat")
	SaveModData(Data, KEY)
end

if GetModConfigData("sw_attack_dist") == "biubiu" then
	DEAR_BTNS:AddDearBtn(GLOBAL.GetInventoryItemAtlas("alterguardianhat_lastprism.tex"), "alterguardianhat_lastprism.tex", "范围追踪", "慕斯专属功能", false,
	 switchKEY)
end
	
AddBindBtn("sw_attack_dist", switchKEY)